package com.jh.user.business.impl;

import cn.jh.common.exception.ServiceException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.jh.user.business.PaymentProfitBusiness;
import com.jh.user.pojo.UserAccount;
import com.jh.user.pojo.payment.PaymentProfit;
import com.jh.user.pojo.payment.PaymentProfits;
import com.jh.user.pojo.payment.PosDTO;
import com.jh.user.pojo.payment.ProfitStatus;
import com.jh.user.repository.PaymentProfitRepository;
import com.jh.user.repository.UserAccountRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;


/**
 * @author Fuchun
 * @since 1.0
 */
@Service("paymentProfitBusiness")
@Transactional(readOnly = true)
public class PaymentProfitBusinessImpl implements PaymentProfitBusiness {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private final Logger logger = LoggerFactory.getLogger(getClass());
    private final PaymentProfitRepository paymentProfitRepository;
    private final UserAccountRepository userAccountRepository;

    @Autowired
    public PaymentProfitBusinessImpl(
            PaymentProfitRepository paymentProfitRepository,
            UserAccountRepository userAccountRepository) {
        this.paymentProfitRepository = paymentProfitRepository;
        this.userAccountRepository = userAccountRepository;
    }

    @Transactional
    public void saveUserAccount(UserAccount account){
        userAccountRepository.save(account);
    }

    public UserAccount findUserAccountByUserid(long userId){
        String sql = "select * from t_user_account where user_id = " + userId ;
        UserAccount userAccount = new UserAccount();
        SqlRowSet set = jdbcTemplate.queryForRowSet(sql);
        while (set.next()){
            userAccount.setId(set.getLong("id"));
            userAccount.setRebateBalance(set.getBigDecimal("rebate_balance"));
            userAccount.setUserId(set.getLong("user_id"));
            userAccount.setSumRebateBalance(set.getBigDecimal("sum_rebate_balance"));
            userAccount.setFreezeBalance(set.getBigDecimal("freeze_balance"));
            userAccount.setFreezerebateBalance(set.getBigDecimal("freeze_rebate_balance"));
            userAccount.setFreezeBalance(set.getBigDecimal("freeze_balance"));
            userAccount.setCoin(set.getInt("coin"));
        }
        return userAccount;
    }

    public UserAccount findUserId(long userId){
        String sql = "select * from t_user_account where user_id = " + userId ;
        UserAccount userAccount = new UserAccount();
        SqlRowSet set = jdbcTemplate.queryForRowSet(sql);
        while (set.next()){
            userAccount.setId(set.getLong("id"));
            userAccount.setRebateBalance(set.getBigDecimal("rebate_balance"));
            userAccount.setUserId(set.getLong("user_id"));
            userAccount.setSumRebateBalance(set.getBigDecimal("sum_rebate_balance"));
            userAccount.setFreezeBalance(set.getBigDecimal("freeze_balance"));
            userAccount.setFreezerebateBalance(set.getBigDecimal("freeze_rebate_balance"));
            userAccount.setFreezeBalance(set.getBigDecimal("freeze_balance"));
            userAccount.setCoin(set.getInt("coin"));
        }
        return userAccount;
    }

    @Override
    @Transactional
    public Long addPaymentProfits(List<PosDTO> posList) {
        if (posList == null || posList.isEmpty()) return 0L;
        List<PaymentProfit> profits = PaymentProfits.fromDto(posList);

        long total = 0;
        for (PaymentProfit profit : profits) {
            paymentProfitRepository.save(profit);
            if (total != 0 && total % 50 == 0) {
                paymentProfitRepository.flush();
            }
            total++;
        }
        return total;
    }

    @Override
    @Transactional(readOnly = true)
    public Page<Long> getInitialPaymentProfits(Pageable pageable) {
        return paymentProfitRepository.queryInitialPosIds(pageable);
    }

    @Override
    @Transactional
    public Long confirmPaymentProfits(Map<Long, Boolean> posIdsToVerifiedMap) {
        if (posIdsToVerifiedMap == null || posIdsToVerifiedMap.isEmpty()) return 0L;
        List<Long> verifiedList = new ArrayList<>(posIdsToVerifiedMap.size());

        long rows = 0;
        for (Map.Entry<Long, Boolean> entry : posIdsToVerifiedMap.entrySet()) {
            if (entry.getKey() == null || entry.getValue() == null) {
                continue;
            }
            if (entry.getValue()) {
                verifiedList.add(entry.getKey());
            }
        }
        if (!verifiedList.isEmpty()) {
            rows = paymentProfitRepository.updateStatusToUnpaid(verifiedList);
        }
        return rows;
    }

    @Override
    @Transactional
    public Page<Long> syncProfitToAccount(Pageable pageable) {
        Page<PaymentProfit> profitPage = paymentProfitRepository.queryInitialProfits(pageable);
        if (!profitPage.hasContent()) {
            if (logger.isDebugEnabled()) {
                logger.debug("No content of the PaymentProfit[status={}]", ProfitStatus.UNPAID);
            }
            return new PageImpl<>(ImmutableList.of(), pageable, 0L);
        }
        Multimap<Long, PaymentProfit> multimap = LinkedHashMultimap.create();
        for (PaymentProfit profit : profitPage.getContent()) {
            multimap.put(profit.getUserId(), profit);
        }

        List<UserAccount> accounts = userAccountRepository.findAllByUserIdIn(
                multimap.keySet(), pageable.getSort());
        List<Long> userIds = new ArrayList<>(accounts.size());
        for (UserAccount account : accounts) {
            Collection<PaymentProfit> profits = multimap.get(account.getUserId());
            if (profits == null || profits.isEmpty()) {
                continue;
            }
            BigDecimal totalProfit = PaymentProfits.sumProfitAndFinished(profits);
            if (totalProfit.compareTo(BigDecimal.ZERO) <= 0) { // 0 分润
                continue;
            }
            account.addProfit(totalProfit);
            userIds.add(account.getUserId());
        }
        userAccountRepository.save(accounts);
        return new PageImpl<>(userIds, pageable, profitPage.getTotalElements());
    }

    /**
     * 查询余额明细
     * @param userId
     * @return
     * @throws ServiceException
     */
    @Override
    public Page<PaymentProfit> queryBalanceDetails(long userId, Pageable pageable) throws ServiceException {
        return paymentProfitRepository.queryBalanceDetails(userId, pageable);
    }
}
